import os
import sys
import platform
import socket
import time
from datetime import datetime
from typing import List
import psutil  # Optional, improves metrics if available
from modules.system.vos.server_vo import (
    CpuInfo,
    MemoryInfo,
    PyInfo,
    SysFiles,
    SysInfo,
    ServerMonitorModel,
)
from utils.common_util import bytes_to_human


_PROCESS_START_TIME = time.time()


class ServerService:
    """
    系统服务监控采集
    """

    @staticmethod
    async def monitor() -> ServerMonitorModel:
        cpu = ServerService._get_cpu_info()
        mem = ServerService._get_memory_info()
        py = ServerService._get_python_info(mem)
        sys = ServerService._get_sys_info()
        files = ServerService._get_sys_files()

        return ServerMonitorModel(cpu=cpu, mem=mem, py=py, sys=sys, sys_files=files)

    @staticmethod
    def _get_cpu_info() -> CpuInfo:
        if psutil:
            cpu_num = psutil.cpu_count(logical=True) or 0
            usage = psutil.cpu_times_percent(interval=0.1)
            used = float(usage.user)
            sys = float(usage.system)
            # idle 可能不存在于极少平台，做保护
            idle = float(getattr(usage, "idle", 0.0))
            free = idle
        else:
            cpu_num = os.cpu_count() or 0
            used = 0.0
            sys = 0.0
            free = 0.0
        return CpuInfo(cpu_num=cpu_num, used=used, sys=sys, free=free)

    @staticmethod
    def _get_memory_info() -> MemoryInfo:
        if psutil:
            vm = psutil.virtual_memory()
            total = bytes_to_human(vm.total)
            used = bytes_to_human(vm.used)
            free = bytes_to_human(vm.available)
            usage = float(vm.percent)
        else:
            # 退化到不可用时返回空/0
            total = None
            used = None
            free = None
            usage = 0.0
        return MemoryInfo(total=total, used=used, free=free, usage=usage)

    @staticmethod
    def _get_python_info(mem: MemoryInfo) -> PyInfo:
        name = "Python"
        version = platform.python_version()
        start_dt = datetime.fromtimestamp(_PROCESS_START_TIME)
        start_time = start_dt.strftime("%Y-%m-%d %H:%M:%S")
        run_seconds = int(time.time() - _PROCESS_START_TIME)
        # 简单格式化运行时长
        days, rem = divmod(run_seconds, 86400)
        hours, rem = divmod(rem, 3600)
        minutes, seconds = divmod(rem, 60)
        run_time = f"{days}d {hours}h {minutes}m {seconds}s"
        home = getattr(sys, "base_prefix", None) or getattr(sys, "prefix", None)
        # 继承 MemoryInfo 字段，保留当前内存使用情况
        return PyInfo(
            name=name,
            version=version,
            start_time=start_time,
            run_time=run_time,
            home=str(home) if home else None,
            total=mem.total,
            used=mem.used,
            free=mem.free,
            usage=mem.usage,
        )

    @staticmethod
    def _get_sys_info() -> SysInfo:
        try:
            hostname = socket.gethostname()
            computer_ip = socket.gethostbyname(hostname)
        except Exception:
            hostname = platform.node()
            computer_ip = None
        os_arch = platform.machine()
        os_name = platform.platform()
        user_dir = os.getcwd()
        return SysInfo(computer_ip=computer_ip, computer_name=hostname, os_arch=os_arch, os_name=os_name, user_dir=user_dir)

    @staticmethod
    def _get_sys_files() -> List[SysFiles]:
        files: List[SysFiles] = []
        if psutil:
            try:
                parts = psutil.disk_partitions(all=False)
                for p in parts:
                    try:
                        u = psutil.disk_usage(p.mountpoint)
                        files.append(
                            SysFiles(
                                dir_name=p.mountpoint,
                                sys_type_name=p.fstype,
                                type_name="local",
                                total=bytes_to_human(u.total),
                                used=bytes_to_human(u.used),
                                free=bytes_to_human(u.free),
                                usage=f"{u.percent:.2f}%",
                            )
                        )
                    except Exception:
                        continue
            except Exception:
                pass
        # 没有 psutil 或调用失败时返回空列表
        return files